import { ElInput } from 'element-plus';
import { debounce } from 'microconnect-common/utils/date';
import { isNumber, isNumberStr } from 'microconnect-common/utils/is';
import {
  divide,
  divide100,
  fixDecimal,
  gt,
  lt,
  minus,
  multiply,
  numThousandthFilter,
  plus,
  round,
  stringOrNumber,
  toNumLocaleString,
  toPercent
} from 'microconnect-common/utils/math';
import { PropType } from 'vue';
import { useFormMode } from '../Form/mode';
import './index.scss';

type TNumType = 'text' | 'number' | 'textarea';

type TLogicFormat = {
  operation: '*' | '+' | '-' | '/' | '%';
  value: number;
};

export const createAppend = (text: string) => {
  return {
    append: () => <span>{text}</span>
  };
};
/**
 * @desc 获取字符串的字节数量
 * @param str
 * @returns
 */
export const getStrByteNumber = (str: string) => {
  return str.replace(/[^\x00-\xff]/g, '**').length;
};
const getNumber = (sourceVal: stringOrNumber) => {
  if (isNumber(sourceVal)) return sourceVal;
  const value = String(sourceVal).replace(/,/g, '');
  if (isNumberStr(value)) {
    return +value;
  }
  return sourceVal;
};
export let MciInput = defineComponent({
  name: 'MciInput',
  props: {
    // 只有下边框单边线
    singleLine: {
      type: Boolean,
      default: false
    },
    prefix: {
      type: String,
      default: ''
    },
    prepend: {
      type: String,
      default: ''
    },
    suffix: {
      type: String,
      default: ''
    },
    append: {
      type: String,
      default: ''
    },
    maxlength: {
      type: [String, Number],
      default: ''
    },
    disabled: {
      type: Boolean,
      default: false
    },
    clearable: {
      type: Boolean,
      default: false
    },
    readonly: {
      type: Boolean,
      default: false
    },
    modelValue: {
      type: [String, Number],
      default: ''
    },
    modelValue2: {
      type: [String, Number],
      default: ''
    },
    toChineseNum: {
      type: Boolean,
      default: false
    },
    /** 延时触发 'change-delay', 'update:modelValue', 'input'事件  */
    delay: {
      type: Number,
      default: 0
    },
    /** 小数精度 -要给input type="number"  不然不生效*/
    decimal: {
      type: Number,
      default: -1
    },
    // 输入框输入类型，只影响能够输入的内容
    type: {
      type: String as PropType<TNumType>,
      default: 'text'
    },
    // 输入限制只能输入整数，当 type 为 number 时生效
    int: {
      type: Boolean,
      default: false
    },
    // 最小值，当 type 为 number 时生效
    min: {
      type: [Number, String],
      default: ''
    },
    // 最大值，当 type 为 number 时生效
    max: {
      type: [Number, String],
      default: ''
    },
    // 格式化输入数值，当 type 为 number 时生效，获取焦点时数值正常，失去焦点时显示千分位分隔
    formatNumLocale: {
      type: Boolean,
      default: false
    },
    // 格式化 输出时带千分位逗号 1,000.00
    isLocaleString: {
      type: Boolean,
      default: false
    },
    localeStringFormat: {
      type: String,
      default: '0,0.00'
    },
    // 以字节限制最大最小输入长度 和 maxlength使用
    byte: {
      type: Boolean,
      default: false
    },
    // 显示模式
    mode: {
      type: String as PropType<TVitalModeType>,
      default: ''
    },
    /** 是否百分比, true: 显示 * 100, 值 / 100 */
    isPercent: {
      type: Boolean,
      default: false
    },
    /** 百分比后再保留小数 要和 isPercent一起用*/
    decimalAfterPercent: {
      type: Boolean,
      default: false
    },
    /** 四舍五入百分比， 要和 isPercent一起用*/
    roundAfterPercent: {
      type: Boolean,
      default: false
    },
    // 百分比处理后隐藏百分号
    hidePercentSuffix: {
      type: Boolean,
      default: false
    },
    /** 是否万为单位, true: 显示 * 10000, 值 / 10000 */
    isW: {
      type: Boolean,
      default: false
    },
    /** 是否转换为大写字母 */
    isUppercase: {
      type: Boolean,
      default: false
    },
    placeholder: {
      type: String,
      default: ''
    },
    rows: {
      type: Number,
      default: 2
    },
    /** 运算格式化 */
    logicFormat: {
      type: Array as PropType<TLogicFormat[]>,
      default: () => []
    },
    isTrim: {
      type: Boolean,
      default: false
    },
    /** 是否百万 */
    isMillion: {
      type: Boolean,
      default: false
    }
  },
  emits: ['change-delay', 'update:modelValue', 'update:modelValue2', 'input', 'blur', 'keydown', 'focus'],
  setup(props, { emit }) {
    const elInput = ref(null as TNullable<any>);
    const value = ref('' as string | number);
    let valClone = '';
    const formMode = useFormMode();

    const filterValue = (val: string) => {
      if (props.type === 'number') {
        // 得到第一个字符是否为负号
        const t = val.charAt(0);
        // 只能输入整数
        if (props.int) {
          val = val.replace(/[^\d]/g, '');
        } else {
          // 先把非数字的都替换掉，除了数字和.
          val = val.replace(/[^\d.]/g, '');
          // 必须保证第一个为数字而不是.
          val = val.replace(/^\./g, '');
          // 保证只有出现一个.而没有多个.
          val = val.replace(/\.{2,}/g, '.');
          // 保证.只出现一次，而不能出现两次以上
          val = val.replace('.', '$#$').replace(/\./g, '').replace('$#$', '.');
        }

        // 如果第一位是负号，则允许添加
        if (t === '-') {
          val = '-' + val;
        }

        // 最大最小值验证，必须是在类型 type 为 number 时才会生效
        const min = props.min;
        const max = props.max;
        // 处理小数0.00的问题
        const decimal = Math.abs(Number(val));
        if (decimal >= 0 && decimal <= 1) {
          return val;
        }
        // 处理小数0.00的问题 结束
        if (min || min === 0) {
          if (val && lt(val, min)) val = String(min);
        }
        if (max || max === 0) {
          if (val && gt(val, max)) val = String(max);
        }
      }

      return val;
    };

    const formatDecimal = (str: string) => {
      if (props.type !== 'number') {
        return str;
      }
      if (props.decimal > -1) {
        const [preValue, decimalStr] = (str + '').split('.');
        const dot = decimalStr === undefined ? '' : '.';
        return preValue + dot + (decimalStr?.slice(0, props.decimal) ?? '');
      }
      return str;
    };

    const byteLogic = (target: string, str: string) => {
      const maxlength = props.maxlength;
      const len = getStrByteNumber(str);

      if (len > maxlength) {
        let index = -1;
        for (let i = 0; i < str.length; i++) {
          const valStr = str.charAt(i);

          if (index !== -1) index = i;

          if (valClone.indexOf(valStr) === -1) index = i;

          if (getStrByteNumber(valClone + valStr) <= maxlength && index !== -1)
            valClone = valClone.slice(0, index) + valStr + valClone.slice(index);
        }

        target = valClone;
      } else {
        if (len === maxlength) {
          target = str;
        } else {
          let count = 0;

          for (let i = 0; i < str.length; i++) {
            count += getStrByteNumber(str.charAt(i));

            if (maxlength >= count) target += str.charAt(i);
          }
        }

        valClone = target;
      }

      return target;
    };

    const handlerTrim = (val: string | number) => {
      if (!isNumber(val) && val && props.isTrim) {
        console.log('val', val.trim());

        return String(val).trim();
      }
      return val;
    };
    const updateVal = (val: string | number, ...args: any[]) => {
      let resultValue = val;

      if (resultValue !== '') {
        const valStr = val + '';
        let target = '';
        if (props.byte) target = byteLogic(target, valStr);
        else target = valStr;

        let result: string | number = filterValue(target);
        value.value = formatDecimal(result);
        resultValue = value.value;
        if (props.isPercent && value.value !== '-' && !/\.$/.test(value.value)) {
          resultValue = divide100(value.value.trim());
        }
      }
      if (props.isMillion && resultValue) {
        resultValue = multiply(toNumLocaleStringReverse(resultValue), 1e6);
      }

      emit('update:modelValue', resultValue);
      emit('input', resultValue, ...args);
    };

    const changeHandle = debounce((val: string, ...args: any[]) => {
      updateVal(val, args);
      emit('change-delay', value.value);
    }, props.delay);

    const numDisabled = computed(() => props.type === 'number' && value.value && props.formatNumLocale);

    const toNumLocaleStringReverse = (val: stringOrNumber) => val.toString().replace(/,/g, '');

    const onBlur = () => {
      if (numDisabled.value) {
        value.value = toNumLocaleString(value.value);
      }

      if (props.type === 'number') {
        // 限制最大最小值
        const val = value.value;
        const min = props.min;
        const max = props.max;
        if (min || min === 0) {
          if (val && lt(val, min)) {
            value.value = String(min);
            emit('update:modelValue', value.value);
          }
        }

        if (max || max === 0) {
          if (val && gt(getNumber(val), max)) {
            value.value = props.formatNumLocale ? toNumLocaleString(max) : String(max);
            emit('update:modelValue', max);
          }
        }
      }
      if (props.isMillion) {
        if (value.value && !isNaN(Number(value.value))) {
          emit('update:modelValue', multiply(toNumLocaleStringReverse(value.value), 1e6));
        }
      }

      if (props.isLocaleString) {
        if (value.value && !isNaN(Number(value.value))) {
          value.value = numThousandthFilter(value.value, props.localeStringFormat);
          emit('update:modelValue', value.value);
        }
      }
      if (props.isTrim) {
        value.value = handlerTrim(value.value);
        emit('update:modelValue', value.value);
      }

      if (props.isW) {
        emit('update:modelValue', multiply(toNumLocaleStringReverse(value.value), 1e4));
      }
      emit('blur');
    };

    const onFocus = (ev: any) => {
      valClone = ev.target.value;

      if (numDisabled.value) {
        value.value = toNumLocaleStringReverse(value.value);
      }
      emit('focus', ev);
    };

    const onKeydown = (ev: any) => {
      emit('keydown', ev);
    };

    const clearHandle = () => changeHandle('');
    // fixed： 输入延迟会导致 validator （change） 获取 value 延迟，导致获取到的是旧的值
    const inputHandle = computed(() => {
      return props.delay === 0 ? updateVal : changeHandle;
    });

    watch(
      () => props.modelValue,
      (val, oldValue) => {
        if (val) {
          if (val === value.value) return;
          if (props.isMillion) {
            if (Number(val) === Number(multiply(toNumLocaleStringReverse(value.value), 1e6))) return;
          }

          value.value = val;

          if (props.isPercent && value.value !== '-' && !/\.$/.test(value.value + '')) {
            if (props.decimalAfterPercent) {
              value.value = toPercent(value.value, props.decimal).replace('%', props.hidePercentSuffix ? '' : '%');
            } else {
              value.value = props.roundAfterPercent
                ? round(multiply(value.value, 100), props.decimal)
                : fixDecimal(multiply(value.value, 100), 2);
            }
          }

          if (props.isMillion) {
            value.value = divide(value.value, 1e6);
          } else if (props.isW) {
            value.value = divide(value.value, 1e4);
          } else if (props.isLocaleString) {
            value.value = numThousandthFilter(value.value, props.localeStringFormat);
          }

          if (props.logicFormat.length && props.type === 'number') {
            props.logicFormat.map(({ operation, value: opValue }) => {
              if (operation) {
                if (operation === '+') {
                  value.value = plus(value.value, opValue);
                } else if (operation === '*') {
                  value.value = multiply(value.value, opValue);
                } else if (operation === '/') {
                  value.value = divide(value.value, opValue);
                } else if (operation === '-') {
                  value.value = minus(value.value, opValue);
                } else if (operation === '%') {
                  value.value = Number(value.value) % Number(opValue);
                }
              }
            });
            updateVal(value.value);
          }

          // if (numDisabled.value && !oldValue) {
          //   value.value = toNumLocaleString(value.value, props.decimal);
          // }
          if (props.int) updateVal(val);
        } else {
          if (props.decimalAfterPercent) {
            value.value = val === 0 ? toPercent(0, props.decimal).replace('%', props.hidePercentSuffix ? '' : '%') : '';
          } else {
            value.value = val || val === 0 ? formatDecimal(val + '') : '';
          }
        }
        // 解决粘贴后，值未格式化问题
        onBlur();
      },
      { immediate: true }
    );

    const inputType = computed(() => {
      if (props.type === 'number') {
        return 'text';
      }
      return props.type;
    });

    const modeComputed = computed(() => formMode?.mode || props.mode);

    return {
      clearHandle,
      inputType,
      elInput,
      value,
      inputHandle,
      onBlur,
      onFocus,
      onKeydown,
      modeComputed
    };
  },
  render() {
    let {
      value,
      inputType,
      prefix,
      prepend,
      suffix,
      append,
      singleLine,
      $slots,
      clearHandle,
      inputHandle,
      onBlur,
      onFocus,
      onKeydown,
      modeComputed,
      decimal
    } = this;

    if (modeComputed === 'view') {
      if (this.formatNumLocale) {
        if (value && !isNaN(Number(value))) {
          decimal = decimal === -1 ? 2 : decimal;
          const decimalFmt = `0,0.${Array(decimal).fill(0).join('')}`;
          value = numThousandthFilter(value, decimalFmt);
        }
      }

      return (
        <span class={['input_view', inputType === 'textarea' && 'textarea-view']}>
          {value ? (
            <>
              {prepend}
              <span v-html={value} />
              {append || (suffix && value && suffix)}
            </>
          ) : (
            '-'
          )}
        </span>
      );
    }

    const disableAttrs = modeComputed === 'disable' || this.disabled ? { disabled: true } : {};

    const createDefaultSlot = (val: string) => (val ? () => val : null);
    const slots: any = {
      prefix: $slots.prefix ?? createDefaultSlot(prefix),
      prepend: $slots.prepend ?? createDefaultSlot(prepend),
      default: $slots.default ?? null,
      suffix: $slots.suffix ?? createDefaultSlot(suffix),
      append: $slots.append ?? createDefaultSlot(append)
    };
    return (
      <ElInput
        ref="elInput"
        v-model={this.value}
        type={inputType}
        readonly={this.readonly}
        maxlength={this.maxlength}
        placeholder={this.placeholder}
        {...this.$attrs}
        {...disableAttrs}
        class={['mci-input', { 'mci-single-line': singleLine, 'is-uppercase': this.isUppercase }]}
        onClear={clearHandle}
        onInput={inputHandle}
        onFocus={onFocus}
        onBlur={onBlur}
        onChange={onBlur}
        onKeydown={onKeydown}
        vSlots={slots}
        rows={this.rows}
        clearable={this.clearable}
      />
    );
  }
});
